﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
using System.Text;

namespace V8.Net
{
    // ========================================================================================================================
#if !(V1_1 || V2 || V3 || V3_5)
    using System.Dynamic;
    using System.Reflection;

    //public unsafe class DynamicHandleMetaObject : DynamicMetaObject
    //{
    //    InternalHandle _Handle;

    //    internal DynamicHandleMetaObject(InternalHandle handle, Expression parameter)
    //        : base(parameter, BindingRestrictions.Empty, handle)
    //    {
    //        _Handle = handle;
    //    }

    //    public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
    //    {
    //        return base.BindGetMember(binder);
    //    }

    //    public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
    //    {
    //        if (_Handle.IsObjectType)
    //        {
    //            V8NetProxy.SetObjectPropertyByName(_Handle, binder.Name, _Handle.Engine.CreateValue(value.Value));
    //            return;
    //        }
    //        return base.BindSetMember(binder, value);
    //    }

    //    public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
    //    {
    //        return base.BindInvoke(binder, args);
    //    }

    //    public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
    //    {
    //        return base.BindInvokeMember(binder, args);
    //    }

    //    public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
    //    {
    //        return base.BindGetIndex(binder, indexes);
    //    }

    //    public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
    //    {
    //        return base.BindSetIndex(binder, indexes, value);
    //    }

    //    public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
    //    {
    //        return base.BindDeleteMember(binder);
    //    }

    //    public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)
    //    {
    //        return base.BindDeleteIndex(binder, indexes);
    //    }

    //    public override IEnumerable<string> GetDynamicMemberNames()
    //    {
    //        return base.GetDynamicMemberNames();
    //    }

    //    public override DynamicMetaObject BindConvert(ConvertBinder binder)
    //    {
    //        if (binder.ReturnType == typeof(string))
    //            return new DynamicMetaObject(Expression, Restrictions, _Handle.AsString);
    //        else
    //            return new DynamicMetaObject(Expression, Restrictions, null);
    //    }
    //}

#else
    public interface IDynamicMetaObjectProvider { }
    public partial class Expression { public static Expression Empty() { return null; } }
    public enum BindingRestrictions { Empty }
    public partial class DynamicMetaObject
    { public DynamicMetaObject(Expression ex, BindingRestrictions rest, object value) { } }
#endif

    // ========================================================================================================================

    public interface IHandleBased
    {
        /// <summary>
        /// Returns the engine associated with this instance.
        /// </summary>
        V8Engine Engine { get; }

        /// <summary>
        /// Returns the underlying handle object associated with this instance.  If no 'Handle' object exists, one is created and returned.
        /// </summary>
        Handle AsHandle();

        /// <summary>
        /// Returns a handle value associated with this instance (note: this is not a clone, but an exact copy).
        /// End users should use "AsHandle", unless they are confident in making sure the InternalHandle they use is properly set and later disposed.
        /// </summary>
        InternalHandle AsInternalHandle { get; }

        /// <summary>
        /// Returns the object for this instance, or 'null' if not applicable/available.
        /// </summary>
        V8NativeObject Object { get; }
    }

    // ========================================================================================================================

    /// <summary>
    /// 跟踪本机V8句柄（C ++本机端）。
    ///当不再使用句柄时，可以在V8.NET系统就绪时处置本机句柄。
    ///如果句柄是一个值，则将立即处理本机句柄端-但是，如果该句柄表示一个托管对象，它将等待直到托管对象
    ///对象也不再使用。
    /// <para>句柄是非常小的值，可以在堆栈上快速传递，因此，垃圾回收器的参与不多。
    ///这有助于防止在进行大量处理时GC介入并降低应用程序速度。
    ///另一个好处是堆内存分配需要线程锁定（出于显而易见的原因），因此在
    ///多线程上下文。</para>
    /// </summary>
    public unsafe class Handle : IHandleBased, IDynamicMetaObjectProvider, IDisposable, IConvertible, IFinalizable
    {
        // --------------------------------------------------------------------------------------------------------------------

        public static readonly Handle Empty = new Handle((HandleProxy*)null);

        // --------------------------------------------------------------------------------------------------------------------
        /// <summary>(仅限'HandleInfo'或'WeakReference<HandleInfo>'类型，对于空/未定义的句柄，则为'null')</summary>
        internal InternalHandle _Handle;

        // --------------------------------------------------------------------------------------------------------------------
        /// <summary>'首先检查'适用于展开的InternalHandle值</summary>
        internal Handle(HandleProxy* hp)
        {
            _Handle._Set(hp, false);
        }

        public Handle(InternalHandle handle)
        {
            _Handle.Set(handle);
        }

        ~Handle()
        {
            if (!((IFinalizable)this).CanFinalize && Engine != null)
                lock (Engine._ObjectsToFinalize)
                {
                    var isLastHandleForObject = (_CurrentObjectID >= 0 && ReferenceCount == 1);
                    if (!isLastHandleForObject) // （应该始终至少是一个与对象关联的句柄）
                        Engine._ObjectsToFinalize.Add(this);
                    GC.ReRegisterForFinalize(this);
                }
        }

        bool IFinalizable.CanFinalize { get { return IsEmpty; } set { } }

        void IFinalizable.DoFinalize()
        {
            _Handle._Dispose(true);
        }

        /// <summary>
        /// 处置当前的句柄代理引用（如果不为空，并且不同），并将其替换为指定的新引用。
        /// <para>注意：设置句柄时必须这样做，否则可能会发生内存泄漏（本机V8句柄永远不会使其回到缓存中）。
        ///切勿使用“ =”运算符设置句柄。 如果使用“ InternalHandle”句柄，则在不再需要它们时始终调用“ Dispose（）”。
        ///为了安全起见，请使用“ using（SomeInternalHandle）{}”语句（带有“ InternalHandle”句柄），或使用“ Handle refHandle = SomeInternalHandle;”
        ///将其转换为将自行处理的句柄对象。</para>
        /// </summary>
        public Handle Set(Handle handle)
        {
            _Handle.Set(handle._Handle);
            return this;
        }

        /// <summary>
        /// 处置当前的句柄代理引用（如果不为空，并且不同），并将其替换为指定的新引用。
        /// <para>注意：设置句柄时必须这样做，否则可能会发生内存泄漏（本机V8句柄永远不会使其回到缓存中）。
        ///切勿使用“ =”运算符设置句柄。 如果使用“ InternalHandle”句柄，则在不再需要它们时始终调用“ Dispose（）”。
        ///为了安全起见，请使用“ using（SomeInternalHandle）{}”语句（带有“ InternalHandle”句柄），或使用“ Handle refHandle = SomeInternalHandle;”
        ///将其转换为将自行处理的句柄对象。</ para>
        /// </summary>
        public Handle Set(InternalHandle handle)
        {
            _Handle.Set(handle);
            return this;
        }
        /// <summary>'首先检查'仅适用于展开的InternalHandle值</summary>
        internal Handle _Set(HandleProxy* hp)
        {
            _Handle._Set(hp, false);
            return this;
        }

        /// <summary>
        /// 创建此句柄的另一个副本，并将引用计数增加到本机句柄。 可以通过两种方式来设置句柄：
        /// 1.通过使用左侧句柄上的'et()'方法，或
        /// 2.使用右侧的'Clone()'方法。使用'='运算符进行设置 如果使用不正确，手柄可能会导致内存泄漏。
        /// 也可以看看: <seealso cref="Set()"/>
        /// </summary>
        public Handle Clone()
        {
            if (_Handle.IsObjectType)
                return new ObjectHandle(_Handle);
            else
                return new Handle(_Handle);
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 尝试处理内部包装的句柄代理并使该句柄为空。
                 ///如果存在其他句柄，那么它们将仍然有效，并且该句柄实例将为空。
                 /// <para>与“ using”语句一起使用以快速将句柄释放到缓存中以供重用时很有用。</para>
        /// </summary>
        public void Dispose() { _Handle._Dispose(false); }

        /// <summary>
        /// 如果已弃置此句柄（不再使用），则返回true。 出于性能原因，已处置的本机代理句柄保留在缓存中。
        /// </summary>
        public bool IsDisposed { get { return _Handle.IsDisposed; } }

        // --------------------------------------------------------------------------------------------------------------------

        public static implicit operator InternalHandle(Handle handle)
        {
            if (handle == null) return InternalHandle.Empty;
            var h = InternalHandle.Empty;
            h._HandleProxy = handle._Handle._HandleProxy; // （这样做是为了防止在隐式转换（开发人员可能不知道）上增加托管引用计数）
            return h;
        }

        public static implicit operator HandleProxy*(Handle handle)
        {
            return handle != null ? handle._Handle._HandleProxy : null;
        }

        public static implicit operator Handle(HandleProxy* handleProxy)
        {
            var h = InternalHandle._WrapOnly(handleProxy);
            if (h.IsObjectType) return new ObjectHandle(handleProxy);
            return h.IsEmpty ? Handle.Empty : new Handle(handleProxy);
        }

        // --------------------------------------------------------------------------------------------------------------------

        public static bool operator ==(Handle h1, Handle h2)
        {
            return (object)h1 == (object)h2 || (object)h1 != null && h1.Equals(h2);
        }

        public static bool operator !=(Handle h1, Handle h2)
        {
            return !(h1 == h2);
        }

        // --------------------------------------------------------------------------------------------------------------------

        public static implicit operator bool(Handle handle)
        {
            return (bool)handle._Handle;
        }

        public static implicit operator Int32(Handle handle)
        {
            return (Int32)handle._Handle;
        }

        public static implicit operator double(Handle handle)
        {
            return (double)handle._Handle;
        }

        public static implicit operator string(Handle handle)
        {
            return (string)handle._Handle;
        }

        public static implicit operator DateTime(Handle handle)
        {
            return (DateTime)handle._Handle;
        }

        public static implicit operator JSProperty(Handle handle)
        {
            return (JSProperty)handle._Handle;
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 对拥有此句柄的V8Engine实例的引用。
        /// </summary>
        public virtual V8Engine Engine { get { return _Handle.Engine; } }

        public Handle AsHandle()
        {
            return this;
        }

        public InternalHandle AsInternalHandle
        {
            get { return (InternalHandle)this; }
        }

        // --------------------------------------------------------------------------------------------------------------------
        #region ### SHARED HANDLE CODE START ###

        /// <summary>
        /// The ID (index) of this handle on both the native and managed sides.
        /// </summary>
        public int ID { get { return _Handle.ID; } }

        /// <summary>
        /// The JavaScript type this handle represents.
        /// </summary>
        public JSValueType ValueType { get { return _Handle.ValueType; } }

        /// <summary>
        /// Used internally to determine the number of references to a handle.
        /// </summary>
        public Int64 ReferenceCount { get { return _Handle.ReferenceCount; } }

        // --------------------------------------------------------------------------------------------------------------------
        // Managed Object Properties and References

        /// <summary>
        /// The ID of the managed object represented by this handle.
        /// This ID is expected when handles are passed to 'V8ManagedObject.GetObject()'.
        /// If this value is less than 0 (usually -1), then there is no associated managed object.
        /// </summary>
        public virtual Int32 ObjectID
        {
            get { return _Handle.ObjectID; }
            internal set { _Handle.ObjectID = value; }
        }

        /// <summary>
        /// Returns the managed object ID "as is".
        /// </summary>
        internal Int32 _CurrentObjectID
        {
            get { return _Handle._CurrentObjectID; }
            set { _Handle._CurrentObjectID = value; }
        }

        /// <summary>
        /// A reference to the managed object associated with this handle. This property is only valid for object handles, and will return null otherwise.
        /// Upon reading this property, if the managed object has been garbage collected (because no more handles or references exist), then a new basic 'V8NativeObject' instance will be created.
        /// <para>Instead of checking for 'null' (which may not work as expected), query 'HasManagedObject' instead.</para>
        /// </summary>
        public V8NativeObject Object { get { return _Handle.Object; } }

        /// <summary>
        /// If this handle represents an object instance binder, then this returns the bound object.
        /// Bound objects are usually custom user objects (non-V8.NET objects) wrapped in ObjectBinder instances.
        /// </summary>
        public object BoundObject { get { return _Handle.BoundObject; } }

        /// <summary>
        /// Returns the registered type ID for objects that represent registered CLR types.
        /// </summary>
        public Int32 CLRTypeID { get { return _Handle.CLRTypeID; } }

        /// <summary>
        /// If this handle represents a type binder, then this returns the associated 'TypeBinder' instance.
        /// <para>Bound types are usually non-V8.NET types that are wrapped and exposed in the JavaScript environment for use with the 'new' operator.</para>
        /// </summary>
        public TypeBinder TypeBinder { get { return _Handle.TypeBinder; } }

        /// <summary>
        /// Returns true if this handle is associated with a managed object.
        /// <para>Note: This can be false even though 'IsObjectType' may be true.
        /// A handle can represent a native V8 object handle without requiring an associated managed object.</para>
        /// </summary>
        public bool HasObject { get { return _Handle.HasObject; } }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// Reading from this property causes a native call to fetch the current V8 value associated with this handle.
        /// <param>For objects, this returns the in-script type text as a string - unless this handle represents an object binder, in which case this will return the bound object instead.</param>
        /// </summary>
        public object Value { get { return _Handle.Value; } }

        /// <summary>
        /// Once "Value" is accessed to retrieve the JavaScript value in real time, there's no need to keep accessing it.  Just call this property
        /// instead (a small bit faster). Note: If the value changes again within the engine (i.e. another scripts executes), you may need to call
        /// 'Value' again to make sure any changes are reflected.
        /// </summary>
        public object LastValue { get { return _Handle.LastValue; } }

        /// <summary>
        /// Returns the array length for handles that represent arrays. For all other types, this returns 0.
        /// </summary>
        public Int32 ArrayLength { get { return _Handle.ArrayLength; } }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// Returns true if this handle is associated with a managed object that has no other references and is ready to be disposed.
        /// </summary>
        public bool IsWeakManagedObject { get { return _Handle.IsWeakManagedObject; } }

        /// <summary>
        /// Returns true if the handle is weak and ready to be disposed.
        /// </summary>
        public bool IsWeakHandle { get { return _Handle.IsWeakHandle; } }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// True if this handle is ready to be disposed (cached) on the native side.
        /// </summary>
        public bool IsInPendingDisposalQueue
        {
            get { return _Handle.IsInPendingDisposalQueue; }
            internal set { _Handle.IsInPendingDisposalQueue = value; }
        }

        /// <summary>
        /// True if this handle was made weak on the native side (for object handles only).  Once a handle is weak, the V8 garbage collector can collect the
        /// handle (and any associated managed object) at any time.
        /// </summary>
        public bool IsNativelyWeak
        {
            get { return _Handle.IsNativelyWeak; }
        }

        /// <summary>
        /// Returns true if this handle is weak AND is associated with a weak managed object reference.
        /// When a handle is ready to be disposed, then calling "Dispose()" will succeed and cause the handle to be placed back into the cache on the native side.
        /// </summary>
        public bool IsDisposeReady { get { return _Handle.IsDisposeReady; } }

        /// <summary>
        /// Attempts to dispose of this handle (add it back into the native proxy cache for reuse).  If the handle represents a managed object,
        /// the dispose request is placed into a "pending disposal" queue. When the associated managed object
        /// no longer has any references, this method will be .
        /// <para>*** NOTE: This is called by Dispose() when the reference count becomes zero and should not be called directly. ***</para>
        /// </summary>
        internal bool __TryDispose() { return _Handle.__TryDispose(); }

        /// <summary>
        /// Completes the disposal of the native handle.
        /// <para>Note: A disposed native handle is simply cached for reuse, and always points back to the same managed handle.</para>
        /// </summary>
        internal void _CompleteDisposal() { _Handle._CompleteDisposal(); }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// Returns true if this handle is empty (that is, equal to 'Handle.Empty'), and false if a valid handle exists.
        /// <para>An empty state is when a handle is set to 'Handle.Empty' and has no valid native V8 handle assigned.
        /// This is similar to "undefined"; however, this property will be true if a valid native V8 handle exists that is set to "undefined".</para>
        /// </summary>
        public bool IsEmpty { get { return _Handle.IsEmpty; } }

        /// <summary>
        /// Returns true if this handle is undefined or empty (empty is when this handle is an instance of 'Handle.Empty').
        /// <para>"Undefined" does not mean "null".  A variable (handle) can be defined and set to "null".</para>
        /// </summary>
        public bool IsUndefined { get { return _Handle.IsUndefined; } }

        /// <summary>
        /// Returns 'true' if this handle represents a 'null' value (that is, an explicitly defined 'null' value).
        /// This will return 'false' if 'IsEmpty' or 'IsUndefined' is true.
        /// </summary>
        public bool IsNull { get { return _Handle.IsNull; } }

        public bool IsBoolean { get { return _Handle.IsBoolean; } }
        public bool IsBooleanObject { get { return _Handle.IsBooleanObject; } }
        public bool IsInt32 { get { return _Handle.IsInt32; } }
        public bool IsNumber { get { return _Handle.IsNumber; } }
        public bool IsNumberObject { get { return _Handle.IsNumberObject; } }
        public bool IsString { get { return _Handle.IsString; } }
        public bool IsStringObject { get { return _Handle.IsStringObject; } }
        public bool IsObject { get { return _Handle.IsObject; } }
        public bool IsFunction { get { return _Handle.IsFunction; } }
        public bool IsDate { get { return _Handle.IsDate; } }
        public bool IsArray { get { return _Handle.IsArray; } }
        public bool IsRegExp { get { return _Handle.IsRegExp; } }

        /// <summary>
        /// Returns true of the handle represents ANY object type.
        /// </summary>
        public bool IsObjectType { get { return _Handle.IsObjectType; } }

        /// <summary>
        /// Used internally to quickly determine when an instance represents a binder object type (faster than reflection!).
        /// </summary>
        public bool IsBinder { get { return _Handle.IsBinder; } }

        /// <summary>
        /// Returns the binding mode (Instance, Static, or None) represented by this handle.  The return is 'None' (0) if not applicable.
        /// </summary>
        public BindingMode BindingMode { get { return _Handle.BindingMode; } }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// Returns the 'Value' property type cast to the expected type.
        /// Warning: No conversion is made between different value types.
        /// </summary>
        public DerivedType As<DerivedType>() { return _Handle.As<DerivedType>(); }

        /// Returns the 'LastValue' property type cast to the expected type.
        /// Warning: No conversion is made between different value types.
        public DerivedType LastAs<DerivedType>() { return _Handle.LastAs<DerivedType>(); }

        /// <summary>
        /// Returns the underlying value converted if necessary to a Boolean type.
        /// </summary>
        public bool AsBoolean { get { return (bool)_Handle; } }

        /// <summary>
        /// Returns the underlying value converted if necessary to an Int32 type.
        /// </summary>
        public Int32 AsInt32 { get { return (Int32)_Handle; } }

        /// <summary>
        /// Returns the underlying value converted if necessary to a double type.
        /// </summary>
        public double AsDouble { get { return (double)_Handle; } }

        /// <summary>
        /// Returns the underlying value converted if necessary to a string type.
        /// </summary>
        public String AsString { get { return (String)_Handle; } }

        /// <summary>
        /// Returns the underlying value converted if necessary to a DateTime type.
        /// </summary>
        public DateTime AsDate { get { return (DateTime)_Handle; } }

        /// <summary>
        /// Returns this handle as a new JSProperty instance with default property attributes.
        /// </summary>
        public IJSProperty AsJSProperty() { return (JSProperty)_Handle; }

        // --------------------------------------------------------------------------------------------------------------------

        public override string ToString() { return _Handle.ToString(); }

        /// <summary>
        /// Checks if the wrapped handle reference is the same as the one compared with. This DOES NOT compare the underlying JavaScript values for equality.
        /// To test for JavaScript value equality, convert to a desired value-type instead by first casting as needed (i.e. (int)jsv1 == (int)jsv2).
        /// </summary>
        public override bool Equals(object obj) { return _Handle.Equals(obj); }

        public override int GetHashCode() { return _Handle.GetHashCode(); }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// Returns true if this handle contains an error message (the string value is the message).
        /// If you have exception catching in place, you can simply call 'ThrowOnError()' instead.
        /// </summary>
        public bool IsError { get { return _Handle.IsError; } }

        /// <summary>
        /// Checks if the handle represents an error, and if so, throws one of the corresponding derived V8Exception exceptions.
        /// See 'JSValueType' for possible exception states.  You can check the 'IsError' property to see if this handle represents an error.
        /// <para>Exceptions thrown: V8InternalErrorException, V8CompilerErrorException, V8ExecutionErrorException, and V8Exception (for any general V8-related exceptions).</para>
        /// </summary>
        public void ThrowOnError() { _Handle.ThrowOnError(); }

        // --------------------------------------------------------------------------------------------------------------------
#if !(V1_1 || V2 || V3 || V3_5)

        public virtual DynamicMetaObject GetMetaObject(Expression parameter)
        {
            if (!IsObjectType)
                return new DynamicMetaObject(parameter, BindingRestrictions.Empty, this); // (there's no object, this is a value type, so just pass along the value)
            return new DynamicHandle(this, parameter);
        }

#endif
        // --------------------------------------------------------------------------------------------------------------------

        public TypeCode GetTypeCode() { return _Handle.GetTypeCode(); }

        public bool ToBoolean(IFormatProvider provider) { return _Handle.ToBoolean(provider); }
        public byte ToByte(IFormatProvider provider) { return _Handle.ToByte(provider); }
        public char ToChar(IFormatProvider provider) { return _Handle.ToChar(provider); }
        public DateTime ToDateTime(IFormatProvider provider) { return _Handle.ToDateTime(provider); }
        public decimal ToDecimal(IFormatProvider provider) { return _Handle.ToDecimal(provider); }
        public double ToDouble(IFormatProvider provider) { return _Handle.ToDouble(provider); }
        public short ToInt16(IFormatProvider provider) { return _Handle.ToInt16(provider); }
        public int ToInt32(IFormatProvider provider) { return _Handle.ToInt32(provider); }
        public long ToInt64(IFormatProvider provider) { return _Handle.ToInt64(provider); }
        public sbyte ToSByte(IFormatProvider provider) { return _Handle.ToSByte(provider); }
        public float ToSingle(IFormatProvider provider) { return _Handle.ToSingle(provider); }
        public string ToString(IFormatProvider provider) { return _Handle.ToString(provider); }
        public object ToType(Type conversionType, IFormatProvider provider) { return _Handle.ToType(conversionType, provider); }
        public ushort ToUInt16(IFormatProvider provider) { return _Handle.ToUInt16(provider); }
        public uint ToUInt32(IFormatProvider provider) { return _Handle.ToUInt32(provider); }
        public ulong ToUInt64(IFormatProvider provider) { return _Handle.ToUInt64(provider); }

        #endregion ### SHARED HANDLE CODE END ###
        // --------------------------------------------------------------------------------------------------------------------
    }

    // ========================================================================================================================

    public interface IV8Object
    {
        bool SetProperty(string name, InternalHandle value, V8PropertyAttributes attributes = V8PropertyAttributes.Undefined);

        /// <summary>
        /// 在基础本机对象上调用V8的“ Set（）”函数。
        ///如果成功，则返回true。
        /// </summary>
        bool SetProperty(Int32 index, InternalHandle value);

        /// <summary>
        /// 将属性设置为给定的对象。 如果该对象与V8.NET不相关，则系统将尝试将实例和所有公共成员绑定到
                 ///指定的属性名称。
                 ///如果成功，则返回true。
        /// </summary>
        /// <param name="name">The property name.</param>
        /// <param name="obj">Some value or object instance. 'Engine.CreateValue()' will be used to convert value types.</param>
        /// <param name="className">A custom in-script function name for the specified object type, or 'null' to use either the type name as is (the default) or any existing 'ScriptObject' attribute name.</param>
        /// <param name="recursive">For object types, if true, then nested objects are included, otherwise only the object itself is bound and returned.</param>
        /// <param name="memberSecurity">Default flags that describe JavaScript properties for all members that don't have any 'ScriptMember' attribute.  They must be 'OR'd together as needed.</param>
        bool SetProperty(string name, object obj, string className = null, bool? recursive = null, ScriptMemberSecurity? memberSecurity = null);

        /// <summary>
        /// 将“ V8Function”对象绑定到指定的类型，并将类型名称（或自定义脚本名称）与基础对象相关联。
                 ///如果成功，则返回true。
        /// </summary>
        /// <param name="type">The type to wrap.</param>
        /// <param name="className">A custom in-script function name for the specified type, or 'null' to use either the type name as is (the default) or any existing 'ScriptObject' attribute name.</param>
        /// <param name="recursive">If true, then nested objects are wrapped as properties are accessed, otherwise only the object itself is bound when created.</param>
        /// <param name="memberSecurity">Default flags that describe JavaScript properties for all members that don't have any 'ScriptMember' attribute.  They must be 'OR'd together as needed.</param>
        bool SetProperty(Type type, string className = null, bool? recursive = null, ScriptMemberSecurity? memberSecurity = null);

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 在基础本机对象上调用V8的'Get()'函数。
        ///如果该属性不存在，则'IsUndefined'属性为true。
        /// </summary>
        InternalHandle GetProperty(string name);

        /// <summary>
        /// 在基础本机对象上调用V8的'Get()'函数。
        ///如果该属性不存在，则'IsUndefined'属性为true。
        /// </summary>
        InternalHandle GetProperty(Int32 index);

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 在基础本机对象上调用V8'Delete()'函数。
        ///如果该属性被删除，则返回true。
        /// </summary>
        bool DeleteProperty(string name);

        /// <summary>
        /// 在基础本机对象上调用V8'Delete（）'函数。
                 ///如果该属性被删除，则返回true。
        /// </summary>
        bool DeleteProperty(Int32 index);

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 在基础本机对象上调用V8'SetAccessor（）'函数，以创建由“ getter”和“ setter”回调控制的属性。
        /// </summary>
        void SetAccessor(string name,
            V8NativeObjectPropertyGetter getter, V8NativeObjectPropertySetter setter,
            V8PropertyAttributes attributes = V8PropertyAttributes.None, V8AccessControl access = V8AccessControl.Default);

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 返回此对象（包括原型链中的所有对象）的所有属性名称的列表。
        /// </summary>
        string[] GetPropertyNames();

        /// <summary>
        /// 返回此对象的所有属性名称的列表（不包括原型链）。
        /// </summary>
        string[] GetOwnPropertyNames();

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 获取此对象的属性的属性标志。
                 ///如果属性不存在，则返回'V8PropertyAttributes.None'
                 ///（注意：只有V8返回“ None”。值“ Undefined”具有内部代理含义，用于拦截属性）。</ para>
        /// </summary>
        V8PropertyAttributes GetPropertyAttributes(string name);

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 调用指定对象上具有给定名称的对象属性作为函数，并返回结果。
                 ///调用时，“ _ this”属性是函数中的“ this”对象。
                 ///如果函数名称为null或为空，则假定当前对象为函数对象。
        /// </summary>
        InternalHandle Call(string functionName, InternalHandle _this, params InternalHandle[] args);

        /// <summary>
        /// 调用指定对象上具有给定名称的对象属性作为函数，并返回结果。
                 ///如果函数名称为null或为空，则假定当前对象为函数对象。
        /// </summary>
        InternalHandle Call(string functionName, params InternalHandle[] args);

        // --------------------------------------------------------------------------------------------------------------------
    }

    // ========================================================================================================================

    public unsafe class ObjectHandle : Handle, IV8Object
    {
        // --------------------------------------------------------------------------------------------------------------------

        new public static ObjectHandle Empty { get { return new ObjectHandle((HandleProxy*)null); } }

        // --------------------------------------------------------------------------------------------------------------------

        internal ObjectHandle(HandleProxy* hp)
            : base(hp)
        {
            if (!IsUndefined && !IsObjectType) throw new InvalidOperationException("本机句柄代理不代表本机对象。");
        }

        public ObjectHandle(InternalHandle handle)
            : base(handle)
        {
            if (!IsUndefined && !IsObjectType) throw new InvalidOperationException("句柄不代表本机对象。");
        }

        // --------------------------------------------------------------------------------------------------------------------

        public static implicit operator ObjectHandle(HandleProxy* handleProxy)
        {
            return handleProxy != null ? new ObjectHandle(handleProxy) : ObjectHandle.Empty;
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 在基础本机对象上调用V8的'Set()'函数。
                 ///如果成功，则返回true。
        /// </summary>
        public virtual bool SetProperty(string name, InternalHandle value, V8PropertyAttributes attributes = V8PropertyAttributes.None)
        {
            return _Handle.SetProperty(name, value, attributes);
        }

        /// <summary>
        /// 在基础本机对象上调用V8的'Set()'函数。
                 ///如果成功，则返回true。
        /// </summary>
        public virtual bool SetProperty(Int32 index, InternalHandle value)
        {
            return _Handle.SetProperty(index, value);
        }

        /// <summary>
        /// 将属性设置为给定的对象。 如果该对象与V8.NET不相关，则系统将尝试将实例和所有公共成员绑定到
                 ///指定的属性名称。
                 ///如果成功，则返回true。
        /// </summary>
        /// <param name="name">属性名称</param>
        /// <param name="obj">一些值或对象实例.'Engine.CreateValue()'将用于转换值类型</param>
        /// <param name="className">自定义类型名称，或为'null'以使用类型名称(默认值)或任何现有的'ScriptObject'属性名称。</param>
        /// <param name="recursive">对于对象实例，如果为true，则包括对象引用成员，否则仅绑定并返回对象本身。
                 ///出于安全原因，指向对象实例的公共成员将被忽略。 包括这些人也必须如此，有效地允许
                 ///对象引用树的脚本内遍历（因此请确保它不会暴露敏感的方法/属性/字段）。</param>
        /// <param name="memberSecurity">描述JavaScript属性的标志。 必须根据需要将它们'或'在一起。</param>
        public bool SetProperty(string name, object obj, string className = null, bool? recursive = null, ScriptMemberSecurity? memberSecurity = null)
        {
            return _Handle.SetProperty(name, obj, className, recursive, memberSecurity);
        }

        /// <summary>
        /// 将'V8Function'对象绑定到指定的类型,并将类型名称(或自定义脚本名称)与基础对象相关联. 如果成功,则返回true.
        /// </summary>
        /// <param name="type">The type to wrap.</param>
        /// <param name="className">A custom type name, or 'null' to use either the type name as is (the default), or any existing 'ScriptObject' attribute name.</param>
        /// <param name="recursive">For object types, if true, then object reference members are included, otherwise only the object itself is bound and returned.
        /// For security reasons, public members that point to object instances will be ignored. This must be true to included those as well, effectively allowing
        /// in-script traversal of the object reference tree (so make sure this doesn't expose sensitive methods/properties/fields).</param>
        /// <param name="memberSecurity">Flags that describe JavaScript properties.  They must be 'OR'd together as needed.</param>
        public bool SetProperty(Type type, string className = null, bool? recursive = null, ScriptMemberSecurity? memberSecurity = null)
        {
            return _Handle.SetProperty(type, className, recursive, memberSecurity);
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 在基础本机对象上调用V8的'Get()'函数。
                 ///如果该属性不存在，则'IsUndefined'属性为true。
        /// </summary>
        public virtual InternalHandle GetProperty(string name)
        {
            return _Handle.GetProperty(name);
        }

        /// <summary>
        /// 在基础本机对象上调用V8的'Get()'函数。
                 ///如果该属性不存在，则'IsUndefined'属性为true。
        /// </summary>
        public virtual InternalHandle GetProperty(Int32 index)
        {
            return _Handle.GetProperty(index);
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        ///在基础本机对象上调用V8'Delete（）'函数。
                 ///如果该属性被删除，则返回true。
        /// </summary>
        public virtual bool DeleteProperty(string name)
        {
            return _Handle.GetProperty(name);
        }

        /// <summary>
        ///在基础本机对象上调用V8'Delete（）'函数。
                 ///如果该属性被删除，则返回true。
        /// </summary>
        public virtual bool DeleteProperty(Int32 index)
        {
            return _Handle.GetProperty(index);
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 在基础本机对象上调用V8'SetAccessor()'函数，以创建由'getter'和'setter'回调控制的属性。
        /// </summary>
        public void SetAccessor(string name,
            V8NativeObjectPropertyGetter getter, V8NativeObjectPropertySetter setter,
            V8PropertyAttributes attributes = V8PropertyAttributes.None, V8AccessControl access = V8AccessControl.Default)
        {
            _Handle.SetAccessor(name, getter, setter, attributes, access);
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 返回此对象（包括原型链中的所有对象）的所有属性名称的列表。
        /// </summary>
        public string[] GetPropertyNames()
        {
            return _Handle.GetPropertyNames();
        }

        /// <summary>
        /// 返回此对象的所有属性名称的列表（不包括原型链）。
        /// </summary>
        public virtual string[] GetOwnPropertyNames()
        {
            return _Handle.GetOwnPropertyNames();
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 获取此对象的属性的属性标志。
                 ///如果属性不存在，则返回'V8PropertyAttributes.None'
                 ///（注意：只有V8返回'None'。值'Undefined'具有内部代理含义，用于拦截属性）。</para>
        /// </summary>
        public V8PropertyAttributes GetPropertyAttributes(string name)
        {
            return _Handle.GetPropertyAttributes(name);
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 调用指定对象上具有给定名称的对象属性作为函数，并返回结果。
                 ///调用时，“ _ this”属性是函数中的“ this”对象。
                 ///如果函数名称为null或为空，则假定当前对象为函数对象。
        /// </summary>
        public virtual InternalHandle Call(string functionName, InternalHandle _this, params InternalHandle[] args)
        {
            return _Handle.Call(functionName, _this, args);
        }

        /// <summary>
        ///调用指定对象上具有给定名称的对象属性作为函数，并返回结果。
                 ///如果函数名称为null或为空，则假定当前对象为函数对象。
        /// </summary>
        public InternalHandle Call(string functionName, params InternalHandle[] args)
        {
            return _Handle.Call(functionName, args);
        }

        // --------------------------------------------------------------------------------------------------------------------
#if !(V1_1 || V2 || V3 || V3_5)

        public override DynamicMetaObject GetMetaObject(Expression parameter)
        {
            return new DynamicHandle(this, parameter);
        }

#endif
        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 对象的原型（每个JavaScript对象都隐含一个原型）。
        /// </summary>
        public ObjectHandle Prototype
        {
            get { return _Handle.Prototype; }
        }

        // --------------------------------------------------------------------------------------------------------------------
    }

    // ========================================================================================================================

    /// <summary>
    /// 这是一个用于内部创建用于动态访问的元对象的类
    /// </summary>
    public sealed class DynamicHandle : DynamicMetaObject
    {
        IV8Object _Handle;
        V8Engine _Engine;

#if (V1_1 || V2 || V3 || V3_5)

        internal DynamicHandle(object value, Expression parameter)
            : base(parameter, BindingRestrictions.Empty, value)
        {
            _Handle = value as IV8Object;
            if (value is IHandleBased) _Engine = ((IHandleBased)value).Engine;
        }

#else

        internal DynamicHandle(object value, Expression parameter)
            : base(parameter, BindingRestrictions.GetTypeRestriction(parameter, value.GetType()), value)
        {
            _Handle = value as IV8Object;
            if (value is IHandleBased) _Engine = ((IHandleBased)value).Engine;
        }

        public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
        {
            if (_Handle == null) throw new InvalidOperationException(InternalHandle._NOT_AN_OBJECT_ERRORMSG);

            Expression[] args = new Expression[1];
            MethodInfo methodInfo = ((Func<string, InternalHandle>)_Handle.GetProperty).Method;

            args[0] = Expression.Constant(binder.Name);

            Expression self = Expression.Convert(Expression, LimitType);

            Expression methodCall = Expression.Call(self, methodInfo, args);

            BindingRestrictions restrictions = Restrictions;

            Func<InternalHandle, object> handleWrapper = h => h.HasObject ? h.Object : (Handle)h; // (need to wrap the internal handle value with an object based handle in order to dispose of the value!)

            return new DynamicMetaObject(Expression.Convert(methodCall, typeof(object), handleWrapper.Method), restrictions);
        }

        public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
        {
            if (_Handle == null) throw new InvalidOperationException(InternalHandle._NOT_AN_OBJECT_ERRORMSG);

            var isHandle = (value.RuntimeType == typeof(InternalHandle) || typeof(Handle).IsAssignableFrom(value.RuntimeType));
            var isV8NativeObject = typeof(V8NativeObject).IsAssignableFrom(value.RuntimeType);

            Expression[] args = new Expression[isHandle || isV8NativeObject ? 3 : 5];
            MethodInfo methodInfo;

            args[0] = Expression.Constant(binder.Name);

            if (isHandle || isV8NativeObject)
            {
                Func<object, InternalHandle> handleParamConversion
                    = obj => (obj is IHandleBased) ? ((IHandleBased)obj).AsInternalHandle
                        : _Engine != null ? _Engine.CreateValue(obj)
                        : InternalHandle.Empty;
                var convertParameter = Expression.Call(Expression.Constant(handleParamConversion.Target), handleParamConversion.Method, Expression.Convert(value.Expression, typeof(object)));
                args[1] = convertParameter;
                args[2] = Expression.Constant(V8PropertyAttributes.None);
                methodInfo = ((Func<string, InternalHandle, V8PropertyAttributes, bool>)_Handle.SetProperty).Method;
            }
            else
            {
                args[1] = Expression.Convert(value.Expression, typeof(object));
                args[2] = Expression.Constant(null, typeof(string));
                args[3] = Expression.Constant(null, typeof(Nullable<bool>));
                args[4] = Expression.Constant(null, typeof(Nullable<ScriptMemberSecurity>));
                methodInfo = ((Func<string, object, string, bool?, ScriptMemberSecurity?, bool>)_Handle.SetProperty).Method;
            }

            Expression self = Expression.Convert(Expression, LimitType);

            Expression methodCall = Expression.Call(self, methodInfo, args);

            BindingRestrictions restrictions = Restrictions.Merge(value.Restrictions);

            return new DynamicMetaObject(Expression.Convert(methodCall, binder.ReturnType), restrictions);
        }

        public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
        {
            return base.BindInvoke(binder, args);
        }

        public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
        {
            return base.BindInvokeMember(binder, args);
        }

        public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
        {
            return base.BindGetIndex(binder, indexes);
        }

        public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
        {
            return base.BindSetIndex(binder, indexes, value);
        }

        public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
        {
            return base.BindDeleteMember(binder);
        }

        public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)
        {
            return base.BindDeleteIndex(binder, indexes);
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            if (_Handle == null) throw new InvalidOperationException(InternalHandle._NOT_AN_OBJECT_ERRORMSG);
            return _Handle.GetPropertyNames();
        }

        public override DynamicMetaObject BindConvert(ConvertBinder binder)
        {
            Expression convertExpression;

            if (LimitType.IsAssignableFrom(binder.Type))
            {
                convertExpression = Expression.Convert(Expression, binder.Type);
            }
            else if (typeof(V8NativeObject).IsAssignableFrom(binder.Type))
            {
                Func<object, V8NativeObject> getUnderlyingObjectMethod = obj => obj is IHandleBased ? ((IHandleBased)obj).Object : null;
                convertExpression = Expression.Convert(Expression.Convert(Expression, typeof(V8NativeObject), getUnderlyingObjectMethod.Method), binder.Type);
            }
            else
            {
                MethodInfo conversionMethodInfo;

                if (binder.Type == typeof(InternalHandle))
                    conversionMethodInfo =
                        ((Func<object, InternalHandle>)(obj => obj is IHandleBased ? ((IHandleBased)obj).AsInternalHandle : InternalHandle.Empty)).Method;
                else if (binder.Type == typeof(Handle))
                    conversionMethodInfo =
                        ((Func<object, Handle>)(obj => obj is IHandleBased ? ((IHandleBased)obj).AsHandle() : Handle.Empty)).Method;
                else
                    conversionMethodInfo = ((Func<object, object>)(obj => Types.ChangeType(Value, binder.Type))).Method;

                convertExpression = Expression.Convert(Expression, binder.Type, conversionMethodInfo);
            }

            BindingRestrictions restrictions = Restrictions.Merge(BindingRestrictions.GetTypeRestriction(convertExpression, binder.Type));

            return new DynamicMetaObject(convertExpression, Restrictions);
        }

#endif
    }

    // ========================================================================================================================
}